`timescale 1 ns /  100 ps
module uart_rx
(
	clock,
	resetn,
	data,
	rx,
	ready
);
// port definition
input clock, resetn, rx;
output reg [7:0] data;
output ready;

// state variables
reg [2:0] state;
reg [2:0] next_state;
parameter IDLE = 3'b000, START = 3'b001, RECEIVE = 3'b010, STOP = 3'b011;

// variables
wire tick_half;
wire tick;
reg [2:0] count;

// state outputs
wire clear_tick_half, clear_tick, clear_count, shift_enable, increment_count;
assign clear_tick_half = (state == IDLE);
assign clear_tick = (state == START && next_state == RECEIVE);
assign clear_count = clear_tick;
assign shift_enable = (state == RECEIVE) && (tick == 1);
assign increment_count = shift_enable;
assign ready = (state == STOP) && (next_state == IDLE) && (rx == 1);

// state transition logic
always @(*)
begin
	case(state)
		IDLE:
			if (rx == 0)
				next_state = START;
			else
				next_state = IDLE;
		START:
			if (tick_half == 1 && rx == 0)
				next_state = RECEIVE;
			else if(tick_half == 1 && rx == 1)
				next_state = IDLE;
			else
				next_state = START;
		RECEIVE:
			if (tick == 1 && count == 3'b111)
				next_state = STOP;
			else
				next_state = RECEIVE;
		STOP:
			if (tick == 1)
				next_state = IDLE;
			else
				next_state = STOP;
	endcase
end

always @(posedge clock or negedge resetn)
begin
	if (resetn == 0)
		state <= IDLE;
	else
		state <= next_state;
end

// tick generator
tick_generator uart_rx_tick_half (.clock(clock), .resetn(resetn), .clear(clear_tick_half), .tick(tick_half));
defparam uart_rx_tick_half.step_size = 20'd4832;
tick_generator uart_rx_tick (.clock(clock), .resetn(resetn), .clear(clear_tick), .tick(tick));
defparam uart_rx_tick.step_size = 20'd2416;

// counter
always @(posedge clock or negedge resetn)
begin
	if (resetn == 0)
		count <= 3'b0;
	else if (clear_count)
		count <= 3'b0;
	else if(increment_count)
		count <= count + 3'b1;
	else
		count <= count;
end

//shift register
always @(posedge clock or negedge resetn)
begin
	if (resetn == 0)
		data <= 8'b0;
	else if (shift_enable)
		data[count] = rx;
end

endmodule